unit edb_obj;

{$mode delphi}{$H+}

interface

uses
windows, windbase, KOL;



const
  { ECEDB exceptions' messages }
  SCannotChangeMountedVolumeName = 'Cannot change volume name while it is mounted.';
  SCannotFindAPIFunctions = 'No API functions found.';
  SVolumeAlreadyMounted = 'Volume already mounted.';
  SVolumeNotMounted = 'Volume not mounted.';
  SVolumeNameNotSet = 'Volume name not set.';
  SDatabaseAlreadyOpened = 'Database already opened.';
  SCannotSetOnActiveDatabase = 'Operation not permitted on open database.';
  SCannotDeleteOpenDatabase = 'Cannot delete open database.';
  SDBaseIsClosed = 'The database is closed.';
  SParamIsNotAssigned = 'One or more parameters are not assigned.';
  SCantDoWhenSessionIsOpen = 'Operation not permitted on open session.';
  SSessionNotOpen = 'Session was not open.';
  SCantSetWhenSessionInTransaction = 'Cannot set when session is in transaction';
  SSessionNotInTransaction = 'Session is not in transaction.';
  SSessionInTransaction = 'Session is already in transaction';
  
  { API returned errors }
  SErrorInvalidParameter = 'Invalid parameter. API: ';
  SErrorBadFormat = 'Bad format. API: ';
  SErrorAccessDenied = 'Access denied. API: ';
  SErrorFileNotFound = 'File not found. API: ';
  SErrorWrongPassword = 'Wrong password. API: ';
  SErrorAlreadyExists = 'Already exists. API: ';
  SErrorNotFound = 'Not found. API: ';
  SErrorOtherAPI = 'Other API error: ';
  SErrorInvalidHandle = 'Invalid handle. API: ';
  SErrorInvalidVolume = 'Invalid volume. API: ';
  SErrorUnableToOpenDatabase = 'Unable to open database. API: ';

  { Some missing API constants }
  ERROR_NOT_FOUND = $0490;

type

{                            TMountOption                                      }

  TMountOption = (moCreateNew, moCreateAlways, moOpenExisting{default}, moOpenAlways, moTruncateExisting);


{                            TCEDBObject                                       }

  TCeDBObject = object(TObj)
  protected
    fLastDBError: KOLString;
    fOID: TCeOID;
    fAPIAvailable:Boolean;
    fOnError: TOnEvent;
    procedure RaiseCEDBException(Msg: KOLString);
  public
    property LastDBError: KOLString read fLastDBError;
    property OID: TCeOID read fOID;
    property OnError: TOnEvent read fOnError write fOnError;
  end;

{                            TCustomCEDBVolume                                 }

  PCustomCEDBVolume = ^TCustomCEDBVolume;

  TCustomCEDBVolume = object(TCeDBObject)
  protected
    fDatabases: PStrListEx;
    fVolumeName: KOLString;
    fMounted: Boolean;
    fCeGuid : PCeGuid;
    fMountOption: TMountOption;
    fBeforeMount: TOnEvent;
    fAftermount: TOnEvent;
    fBeforeUnmount: TOnEvent;
    fAfterUnmount: TOnEvent;
    procedure SetVolumeName(Value: KOLString);
    function GetVolumeName: KOLString;
    function CheckAPI:Boolean; virtual; abstract;
    function GetDatabaseCount: Integer; virtual; abstract;
    function GetDatabaseName(idx: Integer): KOLString; virtual; abstract;
  public
    procedure EnumDatabases; virtual; abstract;
    procedure Mount; virtual; abstract;
    procedure Unmount; virtual; abstract;
    property Mounted:Boolean read fMounted;
    property VolumeName: KOLString read GetVolumeName write SetVolumeName;
    property Guid: PCeGUID read fCeGuid;
    property MountOption: TMountOption read fMountOption write fMountOption;
    property Databases[idx:Integer]: KOLString read GetDatabaseName;
    property DatabaseCount: Integer read GetDatabaseCount;
    property BeforeMount: TOnEvent read fBeforeMount write fBeforeMount;
    property AfterMount: TOnEvent read fAfterMount write fAfterMount;
    property BeforeUnmount: TOnEvent read fBeforeUnmount write fBeforeUnmount;
    property AfterUnmount: TOnEvent read fAfterUnmount write fAfterUnmount;
  end;



{                            TEDBVolumeOptions                                 }


  TEDBVolumeOptions = record
    BufferPool: Longword;
    AutoShrinkPercent: Longword;
    FlushInterval: Longword;
    MaxNotifyChanges: Longword;
    DefaultTimeOut: Longword;
    Password: KOLString;
  end;

{                               TQuickDatabaseInfo                             }

  PEDBDatabaseQuickInfo = ^TEDBDatabaseQuickInfo;

  TEDBDatabaseQuickInfo = object(TObj)
    OID: TCeOID;
    RecordCount: LongWord;
    SortOrderCount: Word;
  end;

{                               TEDBVolume                                     }

  PEDBVolume = ^TEDBVolume;

  TEDBVolume = object(TCustomCEDBVolume)
  private
    fVolumeOptions: TEDBVolumeOptions;
  protected
    function CheckAPI:Boolean; virtual;
    function GetDatabaseCount: Integer; virtual;
    function GetDatabaseName(idx: Integer): KOLString; virtual;
    function GetDatabaseQuickInfo(idx: Integer): PEDBDatabaseQuickInfo;
    procedure EnumDatabases; virtual;
  public
    property VolumeOptions: TEDBVolumeOptions read fVolumeOptions write fVolumeOptions;
    procedure Init; virtual;
    destructor Destroy; virtual;
//    constructor Create;
    procedure Mount; virtual;
    procedure Unmount; virtual;
    function Flush: Boolean;
    property Mounted:Boolean read fMounted;
    property DatabaseQuickInfo[idx: Integer]: PEDBDatabaseQuickInfo read GetDatabaseQuickInfo;
  end;


{                           TCustomCEDBDatabase                                }

  PCustomCEDBDatabase = ^TCustomCEDBDatabase;

  TCustomCEDBDatabase = object(TCEDBObject)
  protected
    fActive: Boolean;
    fDatabaseName: KOLString;
    fVolume: PCustomCEDBVolume;
    fRecordCount: Integer;
    fEOF: Boolean;
    fFields: PList;
    fHandle: Handle;
    procedure SetActive(Value: Boolean); virtual; abstract;
    procedure SetDatabaseName(Value: KOLString);
    procedure SetVolume(Value: PCustomCEDBVolume);
  public
    property Volume: PCustomCEDBVolume read fVolume write SetVolume;
    procedure Init; virtual;
    function Open: Boolean; virtual;
    function Close: Boolean; virtual;
    procedure Next; virtual; abstract;
    procedure Prior; virtual; abstract;
    procedure First; virtual; abstract;
    procedure Last; virtual; abstract;
    procedure Delete; virtual; abstract;
    procedure Append; virtual; abstract;
    procedure Edit; virtual; abstract;
    procedure Post; virtual; abstract;
    property DatabaseName: KOLString read fDatabaseName write SetDatabaseName;
    property Active: Boolean read fActive write SetActive;
    property RecordCount: Integer read fRecordCount;
    property Eof: Boolean read fEof;
  end;

{                           TCEDBPropertyType                                  }

  TCEDBPropertyType = (cedbftBlob, cedbftBool, cedbftFileTime, cedbftWord,
                    cedbftLongword, cedbftString, cedbftFloat, cedftLongInt,
                    cedbftInt64, cedbftStream, cedbftGuid, cedbftAutoLongInt,
                    cedbftAutoInt64);
                    

{                           TCustomCEDBProperty                                }

  TCustomCEDBProperty = object(TCEDBObject)
  protected
    fPropertyName: KOLString;
    fDatabase: PCustomCEDBDatabase;
    fPropertyType: TCEDBPropertyType;
    procedure SetPropertyName(Value: KOLString);
    procedure SetPropertyType(Value: TCEDBPropertyType);
    function GetAsString: KOLString; virtual; abstract;
  public
    fExisting: Boolean; // used internally
    property PropertyName: KOLString read fPropertyName write SetPropertyName;
    property PropertyType: TCEDBPropertyType read fPropertyType write SetPropertyType;
    property AsString: KOLString read GetAsString;
  end;

{                           TEDBSessionIsolationLevel                          }

  TEDBSessionIsolationLevel = (ilDefault, ilReadCommitted, ilRepeatableRead, ilSerializable);


{                           TEDBSession                                        }

  PEDBSession = ^TEDBSession;

  TEDBSession = object(TCEDBObject)
  protected
    fHandle: Handle;
    fInTransaction: Boolean;
    fVolume: PEDBVolume;
    fIsOpen: Boolean;
    fIsoLevel: TEDBSessionIsolationLevel;
    procedure SetIsoLevel(Value: TEDBSessionIsolationLevel);
    function EndTransaction(bCommit: Boolean): Boolean;
  public
    procedure Init; virtual;
    property Handle: Handle read fHandle;
    property IsInTransaction: Boolean read fInTransaction;
    property Volume: PEDBVolume read fVolume write fVolume;
    property IsOpen: Boolean read fIsOpen;
    property IsolationLevel: TEDBSessionIsolationLevel read fIsoLevel write SetIsoLevel;
    function Start: Boolean; virtual;
    function EndCommit: Boolean; virtual;
    function EndRollback: Boolean; virtual;
    procedure Open;
    procedure Close;
  end;

{                           TEDBDatabase                                       }
  
  PEDBDatabase = ^TEDBDatabase;
  
  TEDBDatabase = object(TCustomCEDBDatabase)
  protected
    fSession: PEDBSession;
    procedure SetSession(Value: PEDBSession);
  public
    procedure Init; virtual;
    procedure Open;
    procedure Close;
    property Session: PEDBSession read fSession write SetSession;
  end;

  function NewEDBVolume: PEDBVolume;
  function NewEDBDatabase: PEDBDatabase;
  function NewEDBSession: PEDBSession;
  
implementation

(******************************************************************************)
{                               TCEDBObject                                    }
(******************************************************************************)

(* TCEDBObject.RaiseCEDBException *)
procedure TCEDBObject.RaiseCEDBException(Msg: KOLString);
begin
  fLastDBError := Msg;
  if Assigned(fOnError) then
    fOnError(PObj(@self));
end;

(******************************************************************************)
{                               TCustomCEDBVolume                              }
(******************************************************************************)

(* TEDBVolume.GetVolumeName *)
function TCustomCEDBVolume.GetVolumeName: KOLString;
begin
  Result := fVolumeName;
end;

(* TEDBVolume.SetVolumeName *)
procedure TCustomCEDBVolume.SetVolumeName(Value: KOLString);
begin
  if fMounted then
    RaiseCEDBException(SCannotChangeMountedVolumeName)
  else
    if fVolumeName <> Value then
      fVolumeName := Value;
end;

(******************************************************************************)
{                               TEDBVolume                                     }
(******************************************************************************)

{constructor TEDBVolume.Create;
begin
  inherited;
  Init;
end;}


(* TEDBVolume.Init *)
procedure TEDBVolume.Init;
begin
  inherited;
  fDatabases := NewStrListEx;
  Add2AutoFree(fDatabases);
  fMounted := False;
  New(fCeGUID);
  fMountOption := moOpenExisting;
  fAPIAvailable := CheckAPI;
  fVolumeName := '';
  fVolumeOptions.AutoShrinkPercent := 0;
  fVolumeOptions.BufferPool := 0;
  fVolumeOptions.DefaultTimeOut := 0;
  fVolumeOptions.FlushInterval := 0;
  fVolumeOptions.MaxNotifyChanges := 0;
  fVolumeOptions.Password := '';
end;

(* destructor TEDBVolume.Destroy *)
destructor TEDBVolume.Destroy;
begin
  Dispose(fCeGuid);
  fVolumeOptions.Password := '';
  fVolumeName := '';
  inherited;
end;

(* TEDBVolume.Flush *)
function TEDBVolume.Flush: Boolean;
begin
  Result := CeFlushDBVol(fCeGUID);
end;

(* TEDBVolume.GetDatabaseName *)
function TEDBVolume.GetDatabaseName(idx:Integer):KOLString;
begin
  Result := fDatabases.Items[idx];
end;

(* TEDBVolume.CheckAPI *)
function TEDBVolume.CheckAPI: Boolean;
begin
  Result :=
    (@CeUnmountDBVol <> nil) and
    (@CeMountDBVolEx <> nil) and
    (@CeFindFirstDatabaseEx <> nil) and
    (@CeFindNextDatabaseEx <> nil) and
    (@CeOidGetInfoEx2 <> nil) and
    (@CeGetDBInformationByHandle <> nil) and
    (@CeOpenDatabaseInSession <> nil);
end;

(* TEDBVolume.Mount *)
procedure TEDBVolume.Mount;
var le: Integer;
    pOptions: PCeVolumeOptions;
    dwFlags: DWord;
begin
  if Assigned(fBeforeMount) then
    fBeforeMount(@self);
    
  if (Length(Trim(fVolumeName))=0) then
  begin
    RaiseCEDBException(SVolumeNameNotSet);
    Exit;
  end;

  if fMounted then
  begin
    RaiseCEDBException(SVolumeAlreadyMounted);
    Exit;
  end;

  if not fAPIAvailable then
  begin
    RaiseCEDBException(SCannotFindAPIFunctions);
    Exit;
  end;

  New(pOptions);
  pOptions^.wVersion := CEVOLUMEOPTIONS_VERSION; // constant for EDB
  pOptions^.cbBufferPool := fVolumeOptions.BufferPool;
  pOptions^.dwAutoShrinkPercent := fVolumeOptions.AutoShrinkPercent;
  pOptions^.cMaxNotifyChanges := fVolumeOptions.MaxNotifyChanges;
  pOptions^.dwDefaultTimeout := fVolumeOptions.DefaultTimeOut;
  pOptions^.dwFlushInterval := fVolumeOptions.FlushInterval;
  pOptions^.wszPassword := fVolumeOptions.Password;
  dwFlags := 0;
  if fVolumeOptions.BufferPool > 0 then
    dwFlags := dwFlags or CEDB_BUFFERPOOL;
  if fVolumeOptions.AutoShrinkPercent > 0 then
    dwFlags := dwFlags or CEDB_AUTOSHRINKPERCENT;
  if fVolumeOptions.FlushInterval > 0 then
    dwFlags := dwFlags or CEDB_FLUSHINTERVAL;
  if fVolumeOptions.MaxNotifyChanges > 0 then
    dwFlags := dwFlags or CEDB_MAXNOTIFYCHANGES;
  if fVolumeOptions.DefaultTimeout > 0 then
    dwFlags := dwFlags or CEDB_DEFAULTTIMEOUT;
  if fVolumeOptions.Password <> '' then
    dwFlags := dwFlags or CEDB_PASSWORD;
  pOptions^.dwFlags := dwFlags;
  case fMountOption of
    moOpenExisting: dwFlags := OPEN_EXISTING;
    moOpenAlways: dwFlags := OPEN_ALWAYS;
    moCreateAlways: dwFlags := CREATE_ALWAYS;
    moCreateNew: dwFlags := CREATE_NEW;
    moTruncateExisting: dwFlags := TRUNCATE_EXISTING;
  end;

  fMounted := CeMountDBVolEx(fCeGuid, PWChar(fVolumeName), pOptions, dwFlags);

  Dispose(pOptions);
  if fMounted then
  begin
    EnumDatabases;
    if Assigned(fAfterMount) then
      fAfterMount(@self);
  end
  else
  begin
    le := GetLastError;
    case le of
      ERROR_INVALID_PARAMETER: RaiseCEDBException(SErrorInvalidParameter + Int2Str(le));
      ERROR_BAD_FORMAT: RaiseCEDBException(SErrorBadFormat + Int2Str(le));
      ERROR_FILE_NOT_FOUND: RaiseCEDBException(SErrorFileNotFound + Int2Str(le));
      ERROR_ACCESS_DENIED: RaiseCEDBException(SErrorAccessDenied + Int2Str(le));
      ERROR_WRONG_PASSWORD: RaiseCEDBException(SErrorWrongPassword + Int2Str(le));
      ERROR_ALREADY_EXISTS: RaiseCEDBException(SErrorAlreadyExists + Int2Str(le));
    end;
  end;
end;

(* TEDBVolume.Unmount *)
procedure TEDBVolume.Unmount;
var le: Integer;
begin
  if Assigned(fBeforeUnmount) then
    fBeforeUnmount(@self);

  if not fMounted then
  begin
    RaiseCEDBException(SVolumeNotMounted);
    Exit;
  end;

  fMounted := not CeUnmountDBVol(fCeGuid);

  if fMounted then
  begin
    le := GetLastError;
    case le of
      ERROR_INVALID_PARAMETER: RaiseCEDBException(SErrorInvalidParameter + Int2Str(le));
      ERROR_NOT_FOUND: RaiseCEDBException(SErrorNotFound + Int2Str(le));
    end;
  end
  else
    if Assigned(fAfterUnmount) then
      fAfterUnmount(@self);
end;

(* TEDBVolume.EnumDatabases *)
procedure TEDBVolume.EnumDatabases;
var hEnum: Handle;
    dbOID: TCeOID;
    pdbInfo: PCeOIDInfoEx;
    pQuickInfo: PEDBDatabaseQuickInfo;
begin
  dbOID := 0;
  fDatabases.Clear;
  hEnum := CeFindFirstDatabaseEx(fCeGuid, 0);
  New(pdbInfo);
  pdbInfo^.wVersion := 2;
  if hEnum <> INVALID_HANDLE_VALUE then
    dbOID := CeFindNextDatabaseEx(hEnum, nil);
  while dbOID <> 0 do
  begin
    if CeOIDGetInfoEx2(fCeGuid, dbOID, pdbInfo) then
    begin
      New(pQuickInfo, Create);
      pQuickInfo^.OID := dbOID;
      pQuickInfo^.RecordCount := pdbInfo^.infDatabase.dwNumRecords;
      pQuickInfo^.SortOrderCount := pdbInfo^.infDatabase.wNumSortOrder;
      fDatabases.Add2AutoFree(pQuickInfo);
      fDatabases.AddObject(pdbInfo^.infDatabase.szDatabaseName, LongWord(pQuickInfo));
    end;
    dbOID := CeFindNextDatabaseEx(hEnum, nil);
  end;
  Dispose(pdbInfo);
  windows.CloseHandle(hEnum);
end;

(* TEDBVolume.GetDatabaseCount *)
function TEDBVolume.GetDatabaseCount:Integer;
begin
    Result := fDatabases.Count;
end;

(* TEDBVolume.GetDatabaseQuickInfo *)
function TEDBVolume.GetDatabaseQuickInfo(idx: Integer): PEDBDatabaseQuickInfo;
begin
  Result := PEDBDatabaseQuickInfo(fDatabases.Objects[idx]);
end;

(******************************************************************************)
{                           TCustomCEDBDatabase                                }
(******************************************************************************)

(* TCustomCEDBDatabase.Init *)
procedure TCustomCEDBDatabase.Init;
begin
  inherited;
  fActive := False;
  fDatabaseName := '';
  fRecordCount := 0;
  fEOF := False;
  fVolume := nil;
  fHandle := ERROR_INVALID_HANDLE;
end;

(* TCustomCEDBDatabase.Open *)
function TCustomCEDBDatabase.Open: Boolean;
begin
  Result := Assigned(fVolume);
  if not result then
  begin
    RaiseCEDBException(SParamIsNotAssigned);
    Exit;
  end;
  Result := not fActive;
  if not Result then
    RaiseCEDBException(SDatabaseAlreadyOpened);
end;

(* TCustomCEDBDatabase.Close *)
function TCustomCEDBDatabase.Close: Boolean;
begin
  Result := fActive;
  if not Result then
    RaiseCEDBException(SDBaseIsClosed);
end;

(* TCustomCEDBDatabase.SetVolume *)
procedure TCustomCEDBDatabase.SetVolume(Value: PCustomCEDBVolume);
begin
  if fActive then
    RaiseCEDBException(SCannotSetOnActiveDatabase)
  else
    if Assigned(Value) then
      fVolume := Value
    else
      RaiseCEDBException(SParamIsNotAssigned);
end;

(* TCustomCEDBDatabase.SetDatabaseName *)
procedure TCustomCEDBDatabase.SetDatabaseName(Value: KOLString);
begin
  if fActive then
    RaiseCEDBException(SCannotSetOnActiveDatabase)
  else
    fDatabaseName := Value;
end;

(******************************************************************************)
{                           TCustomCEDBProperty                                }
(******************************************************************************)

(* TCustomCEDBField.SetFieldName *)
procedure TCustomCEDBProperty.SetPropertyName(Value: KOLString);
begin
  if fDatabase.Active then
    RaiseCEDBException(SCannotSetOnActiveDatabase)
  else
    fPropertyName := Value;
end;

(* TCustomCEDBField.SetFieldType *)
procedure TCustomCEDBProperty.SetPropertyType(Value: TCEDBPropertyType);
begin
  if fDatabase.Active then
    RaiseCEDBException(SCannotSetOnActiveDatabase)
  else
    fPropertyType := Value;
end;

(******************************************************************************)
{                           TEDBDatabase                                       }
(******************************************************************************)

(* TEDBDatabase.SetSession *)
procedure TEDBDatabase.SetSession(Value: PEDBSession);
begin
  if fActive then
    RaiseCEDBException(SCannotSetOnActiveDatabase)
  else
    if Assigned(Value) then
      fSession := Value
    else
      RaiseCEDBException(SParamIsNotAssigned);
end;

(* TEDBDatabase.Init *)
procedure TEDBDatabase.Init;
begin
  inherited;
  fSession := nil;
end;

(* TEDBDatabase.Open *)
procedure TEDBDatabase.Open;
var InSession: Boolean;
    hSess: Handle;
    pOid: PCEOID;
    le: Integer;
begin
  if inherited Open then
  begin
    if Assigned(fSession) and (fSession.IsOpen) then
      hSess := fSession.Handle
    else
      hSess := 0;
    New(pOid);
    fHandle := CeOpenDatabaseInSession(hSess, fVolume.Guid, pOid, PWChar(fDatabaseName), nil, CEDB_AUTOINCREMENT, nil);
    if fHandle = ERROR_INVALID_HANDLE then
    begin
      le := GetLastError;
      RaiseCEDBException(SErrorUnableToOpenDatabase+Int2Str(le));
      fActive := False;
    end
    else
    begin
      fOid := Unaligned(pOid^);
      fActive := True;
    end;
    Dispose(pOid);
  end;
end;

(* TEDBDatabase.Close *)
procedure TEDBDatabase.Close;
begin
  if inherited Close then
  begin
    CloseHandle(fHandle);
    fActive := False;
  end;
end;

(******************************************************************************)
{                           TEDBSession                                        }
(******************************************************************************)

(* TEDBSession.Init *)
procedure TEDBSession.Init;
begin
  inherited;
  fHandle := ERROR_INVALID_HANDLE;
  fInTransaction := False;
  fIsOpen := False;
  fVolume := nil;
  fIsoLevel := ilDefault;
end;

(* TEDBSession.Open *)
procedure TEDBSession.Open;
var le: Integer;
begin
  if fIsOpen then
    RaiseCEDBException(SCantDoWhenSessionIsOpen)
  else
    if not Assigned(fVolume) then
      RaiseCEDBEXception(SParamIsNotAssigned)
    else
      begin
        fHandle := CeCreateSession(fVolume.Guid);
        if fHandle = ERROR_INVALID_HANDLE then
        begin
          le := GetLastError;
          RaiseCEDBException(SErrorInvalidVolume+Int2Str(le));
        end;
        fIsOpen := fHandle <> ERROR_INVALID_HANDLE;
      end;
end;

(* TEDBSession.Close *)
procedure TEDBSession.Close;
begin
  if not fIsOpen then
    RaiseCEDBException(SSessionNotOpen)
  else
    begin
      CloseHandle(fHandle);
      fIsOpen := False;
      fInTransaction := False;
    end;
end;

(* TEDBSession.SetIsoLevel *)
procedure TEDBSession.SetIsoLevel(Value: TEDBSessionIsolationLevel);
begin
  if fInTransaction then
    RaiseCEDBEXception(SCantSetWhenSessionInTransaction)
  else
    fIsoLevel := Value;
end;

(* TEDBSession.EndTransaction *)
function TEDBSession.EndTransaction(bCommit: Boolean): Boolean;
begin
  Result := False;
  if not fInTransaction then
    RaiseCEDBException(SSessionNotInTransaction)
  else
    Result := CeEndTransaction(fHandle, bCommit);
end;

(* TEDBSession.Start *)
function TEDBSession.Start: Boolean;
var iIsoLevel: Integer;
    le: Integer;
begin
  Result := False;
  if not fIsOpen then
    RaiseCEDBException(SSessionNotOpen)
  else
    if fInTransaction then
      RaiseCEDBException(SSessionInTransaction)
    else
      begin
        case fIsoLevel of
          ilDefault: iIsoLevel := CEDB_ISOLEVEL_DEFAULT;
          ilReadCommitted: iIsoLevel := CEDB_ISOLEVEL_READCOMMITTED;
          ilRepeatableRead: iIsoLEvel := CEDB_ISOLEVEL_REPEATABLEREAD;
          ilSerializable: iIsoLevel := CEDB_ISOLEVEL_SERIALIZABLE;
        end;
        Result := CeBeginTransaction(fHandle, iIsoLevel);
      end;
end;

(* TEDBSession.EndCommit *)
function TEDBSession.EndCommit: Boolean;
begin
  Result := EndTransaction(True);
end;

(* TEDBSession.EndRollback *)
function TEDBSession.EndRollback: Boolean;
begin
  Result := EndTransaction(False);
end;

(******************************************************************************)

(* function NewEDBVolume *)
function NewEDBVolume: PEDBVolume;
begin
  New(Result, Create);
end;

(* function NewEDBDatabase *)
function NewEDBDatabase: PEDBDatabase;
begin
  New(Result, Create);
end;

(* function NewEDBSession *)
function NewEDBSession: PEDBSession;
begin
  New(Result, Create);
end;
end.

